<?php

/**
 * This class allows arrays to work as object;
 */
class XArrayObject implements ArrayAccess,Countable {
    private $storage;
    protected $elementObjectName = 'XArrayElementObject';
    protected $storageType = 'ArrayObject';
    protected $indexType = 'hex';
    public function __construct($array) {
        $this->storage = $this->getStorageObject();
        foreach($array as $key => $value) {
            if(is_array($value)) {
                $key = $this->getIndex($key);
                $this->storage->offsetSet($key,new XArrayObject($value));
            } else {
                $this->setKeyValue($key,$value);
            }
        }
    }
    public function getStorageObject() {
        $ref = new ReflectionClass($this->storageType);
        return $ref->newInstance();
    }
    public function setElement($value, $sKey = '') {
        $ref = new ReflectionClass($this->elementObjectName);
        return $ref->newInstance($value,$sKey);
    }
    public function getIndex($str_key) {
        $int_hash = 0;
        $key_len = strlen($str_key);
        for($i=0;$i<$key_len;$i++) {
            $int_hash = ((($int_hash <<5) + $int_hash) + ord($str_key[$i])) % 5813;
        }
        return $this->indexType == 'hex'? dechex($int_hash) : $int_hash;
    }
    public function offsetExists($str_index) {
        $index = $this->getIndex($str_index);
        return $this->storage->offsetExists($index);
    }
    public function offsetGet($str_index) {
        $index = $this->getIndex($str_index);
        return $this->storage->offsetGet($index);
    }
    public function count() {
        return $this->storage->count();
    }
    public function offsetUnset($sKey) {
        $this->stroage->offsetUnset($int_key);
    }
    public function setKeyValue($sKey,$value) {
        $key = $this->getIndex($sKey);
        if(is_array($value)) {
            $this->storage->offsetSet($key,new XArrayObject($value));
        } else {
            $this->storage->offsetSet($key, $this->setElement($value,$sKey));
        }
    }
    public function offsetSet($sKey, $value) {
        $this->setKeyValue($sKey,$value);
    }
    public function __set($sKey, $value) {
        $this->setKeyValue($sKey,$value);
    }
    public function __get($sKey) {
        return $this->offsetGet($sKey);
    }
    public function __isset($sKey) {
        return $this->offsetExists($sKey);
    }
    public function __unset($sKey) {
        $this->offsetUnset($sKey);
    }

}
